package com.hex.ds.code.detection.pack.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import com.hex.ds.code.detection.common.entity.ScriptPackScanItemEntity;
import com.hex.ds.code.detection.common.entity.ScriptPackScanResultEntity;
import com.hex.ds.code.detection.common.utils.SqlFormatterUtil;
import com.hex.ds.code.detection.pack.entity.ScriptPackScanListEntity;
import com.hex.ds.code.detection.pack.entity.ScriptPackTaskEntity;
import com.hex.ds.code.detection.pack.enums.FileScanEnum;
import com.hex.ds.code.detection.pack.service.IScanScriptFileService;
import com.hex.ds.code.detection.pack.service.IScriptPackScanItemService;
import com.hex.ds.code.detection.pack.service.IScriptPackScanListService;
import com.hex.ds.code.detection.pack.service.IScriptPackScanResultService;
import com.hex.ds.code.detection.pack.service.IScriptPackTaskService;
import com.hex.ds.code.detection.hive.service.HiveBaseSqlVisitor;
import com.hex.ds.code.detection.oracle.service.OracleBasicSqlVisitor;
import com.hex.ds.code.detection.pack.service.ISQLExtractor;
import com.hex.ds.code.detection.publish.service.ConfigService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Slf4j
@Service
@RequiredArgsConstructor(onConstructor_ = {@Lazy, @Autowired})
public class ScanScriptFileServiceImpl implements IScanScriptFileService {

    private final ApplicationContext applicationContext;

    private final IScriptPackScanListService scriptPackScanListService;

    private final IScriptPackScanResultService scriptPackScanResultService;

    private final IScriptPackScanItemService scriptPackScanItemService;

    private final IScriptPackTaskService scriptPackTaskService;

    private final ISQLExtractor isqlExtractor;

    private final ConfigService configService;


    /**
     * @Method scanInitScriptFile
     * @Param
     * @param scriptPackScanItemList
     * @param scriptPackScanList
     * @Return void
     * @Description 异步扫描初始化脚本文件
     * @Author Wang zhihao
     * @Date 2023/10/9 11:33
     * @Version V1.0
     */
    @Override
    @Async("scriptScanAsyncTaskExecutor")
    public void scanInitScriptFile(List<ScriptPackScanItemEntity> scriptPackScanItemList, List<ScriptPackScanItemEntity> scriptPackScanHqlItemList, ScriptPackScanListEntity scriptPackScanList, List<String> timePartitionTableList, String clusterName) {
        List<ScriptPackScanResultEntity> fileAllScanResult = new ArrayList<>();
        scriptPackScanListService.updateStatus(scriptPackScanList.getId(), "SCANNING");
        log.info("==========【初始化脚本文件" +scriptPackScanList.getScanFileName()+ "扫描开始】==========");
        try {
            List<String> sourceSqlList = getSqlByReadFile(scriptPackScanList.getScanFilePath());
            for (int i=0; i < sourceSqlList.size() ; i++) {
                // 初始化脚本扫描对象
                Map<String, ScriptPackScanResultEntity> scriptPackScanResultMap = initInitScript(scriptPackScanItemList, scriptPackScanHqlItemList, scriptPackScanList);
                try {
                    Map<String, List<ScriptPackScanResultEntity>> scriptPackScanItemResultMap = getScanResultMap(sourceSqlList.get(i), scriptPackScanList.getScanFilePath(), scriptPackScanList.getScanFileName(), scriptPackScanResultMap, timePartitionTableList, clusterName);
                    List<ScriptPackScanResultEntity> scriptPackScanItemResult = CollUtil.getFirst(scriptPackScanItemResultMap.values());
                    String resultSql = CollUtil.getFirst(scriptPackScanItemResultMap.keySet());
                    fileAllScanResult.addAll(scriptPackScanItemResult);
                    jointInfo(scriptPackScanItemResult, scriptPackScanList.getScanFileName(), scriptPackScanList.getId(), resultSql, i+1, "init");
                } catch (Exception e) {
                    log.error("初始化脚本文件["+ scriptPackScanList.getScanFileName() +"]第[" + i+1 + "]块解析异常,请检查SQL是否规范");
                    List<ScriptPackScanResultEntity> scriptPackScanItemResult = new ArrayList<>(scriptPackScanResultMap.values())
                            .stream().map(s -> s.setScanState("antlrFail")).collect(Collectors.toList());
                    fileAllScanResult.addAll(scriptPackScanItemResult);
                    jointInfo(scriptPackScanItemResult, scriptPackScanList.getScanFileName(), scriptPackScanList.getId(), sourceSqlList.get(i), i+1, "init");
                }
            }
            String lastState = updateScanStatus(scriptPackScanList.getId(), fileAllScanResult, "success");
            updateTaskStateNum(scriptPackScanList.getScriptPackTaskId(), lastState);
        } catch (Exception e) {
            log.error("初始化脚本文件["+ scriptPackScanList.getScanFileName() +"]扫描出现异常：{}", e.getMessage(), e);
            scriptPackScanListService.updateStatus(scriptPackScanList.getId(), "FAIL");
            scriptPackTaskService.modifyScanErrorNum(scriptPackScanList.getScriptPackTaskId());
        }
    }

    /**
     * @Method scanShellScriptFile
     * @Param
     * @param scriptPackScanShellItemList
     * @param scriptPackScanList
     * @Return String
     * @Description 异步扫描Shell脚本文件
     * @Author Wang zhihao
     * @Date 2024/1/29 19:40
     * @Version V1.0
     */
    @Override
    @Async("scriptScanAsyncTaskExecutor")
    public void scanShellScriptFile(List<ScriptPackScanItemEntity> scriptPackScanShellItemList, ScriptPackScanListEntity scriptPackScanList) {
        scriptPackScanListService.updateStatus(scriptPackScanList.getId(), "SCANNING");
        log.info("==========【初始化Shell脚本文件" +scriptPackScanList.getScanFileName()+ "扫描开始】==========");
        try {
            // 初始化脚本扫描对象
            Map<String, ScriptPackScanResultEntity> scriptPackScanResultMap = initShellScript(scriptPackScanShellItemList, scriptPackScanList.getScriptPackTaskId());
            String scanFileTypeResult = scanShellFileType(scriptPackScanResultMap, scriptPackScanList);
            scriptPackScanListService.updateStatus(scriptPackScanList.getId(), scanFileTypeResult.toUpperCase(Locale.ROOT));
            updateTaskStateNum(scriptPackScanList.getScriptPackTaskId(), scanFileTypeResult);
        } catch (Exception e) {
            log.error("Shell脚本文件["+ scriptPackScanList.getScanFileName() +"]扫描出现异常：{}", e.getMessage(), e);
            scriptPackScanListService.updateStatus(scriptPackScanList.getId(), "FAIL");
            scriptPackTaskService.modifyScanErrorNum(scriptPackScanList.getScriptPackTaskId());
        }
    }

    /**
     * @Method scanShellFileType
     * @Param
     * @param scriptPackScanResultMap
     * @param scriptPackScanList
     * @Return java.lang.String
     * @Description 扫描Shell脚本文件类型
     * @Author Wang zhihao
     * @Date 2024/1/30 10:53
     * @Version V1.0
     */
    private String scanShellFileType(Map<String, ScriptPackScanResultEntity> scriptPackScanResultMap, ScriptPackScanListEntity scriptPackScanList) {
        if (scriptPackScanList.getScanFileName().endsWith(".sh") && scriptPackScanResultMap.containsKey(
            FileScanEnum.SHELL_FILE_TYPE_CHECK.getValue())){
            ScriptPackScanResultEntity scriptPackScanResult = scriptPackScanResultMap.get(FileScanEnum.SHELL_FILE_TYPE_CHECK.getValue());
            // 读取脚本文件内容
            String sourceSql = FileUtil.readUtf8String(scriptPackScanList.getScanFilePath());
            try {
                // 获取文件类型
                String fileType = getShellFileType(scriptPackScanList.getScanFilePath());
                log.info(StrUtil.format("获取文件{}类型成功【{}】，开始校验其是否符合规定", scriptPackScanList.getScanFilePath(), fileType));
                // 是否为Linux类型文件
                boolean isLinuxType = StrUtil.equals(fileType, "linux");
                // 返回扫描结果信息
                log.info(StrUtil.format("返回文件{}扫描结果开始", scriptPackScanList.getScanFilePath()));
                // 存储信息
                addScanResultInfo("", scriptPackScanResult, scriptPackScanList, isLinuxType, scriptPackScanResult.getScanLevel());
                // 存储原扫描sql
                saveScanSql(scriptPackScanResult, sourceSql);
                log.info(StrUtil.format("返回文件{}扫描结果到result表成功", scriptPackScanList.getScanFilePath()));
                return isLinuxType ? "SUCCESS" : ( StrUtil.equalsIgnoreCase(scriptPackScanResult.getScanLevel(), "necessary") ? "FAIL" : "WARNING" );
            } catch (Exception e) {
                log.error("扫描Shell脚本文件类型异常: {}", e.getMessage(), e);
                // 存储信息
                addScanResultInfo("", scriptPackScanResult, scriptPackScanList, "error");
                // 存储原扫描sql
                saveScanSql(scriptPackScanResult, sourceSql);
                throw new RuntimeException("扫描Shell脚本文件类型异常: " + e.getMessage(), e);
            }
        } else {
            return "success";
        }
    }

    /**
     * @Method saveScanSql
     * @Param
     * @param scriptPackScanResult
     * @param scanSql
     * @Return void
     * @Description 存储原扫描sql
     * @Author Wang zhihao
     * @Date 2024/3/14 14:46
     * @Version V1.0
     */
    private void saveScanSql(ScriptPackScanResultEntity scriptPackScanResult, String scanSql) {
        try {
            scriptPackScanResult.setScanSql(scanSql);
            scriptPackScanResultService.updateById(scriptPackScanResult);
        } catch (Exception e) {
            log.error(StrUtil.format("原脚本文件{}-内容存储到数据库时出现问题", scriptPackScanResult.getFileName()), e.getMessage(), e);
            scriptPackScanResult.setScanSql("原脚本文件内容存储入数据库出现问题");
            scriptPackScanResultService.updateById(scriptPackScanResult);
        }
    }

    /**
     * @Method scanServiceScriptFile
     * @Param
     * @param scriptPackScanItemList
     * @param scriptPackScanList
     * @Return void
     * @Description 异步扫描业务脚本文件
     * @Author Wang zhihao
     * @Date 2023/10/12 17:43
     * @Version V1.0
     */
    @Override
    @Async("scriptScanAsyncTaskExecutor")
    public void scanServiceScriptFile(List<ScriptPackScanItemEntity> scriptPackScanItemList, ScriptPackScanListEntity scriptPackScanList, String clusterName) {
        List<ScriptPackScanResultEntity> fileAllScanResult = new ArrayList<>();
        scriptPackScanListService.updateStatus(scriptPackScanList.getId(), "SCANNING");
        log.info("==========【业务脚本文件" +scriptPackScanList.getScanFileName()+ "扫描开始】==========");
        try {
            List<String> sourceSqlList = getSqlByReadFileNoSplit(scriptPackScanList.getScanFilePath());
            for (int i=0; i < sourceSqlList.size() ; i++) {
                // 初始化脚本扫描对象
                Map<String, ScriptPackScanResultEntity> scriptPackScanResultMap = initServiceScript(scriptPackScanItemList, scriptPackScanList.getScriptPackTaskId());
                try {
                    Map<String, List<ScriptPackScanResultEntity>> scriptPackScanItemResultMap = getScanOracleResultMap(sourceSqlList.get(i), scriptPackScanList.getScanFilePath(), scriptPackScanResultMap, clusterName);
                    List<ScriptPackScanResultEntity> scriptPackScanItemResult = CollUtil.getFirst(scriptPackScanItemResultMap.values());
                    String resultSql = CollUtil.getFirst(scriptPackScanItemResultMap.keySet());
                    fileAllScanResult.addAll(scriptPackScanItemResult);
                    jointInfo(scriptPackScanItemResult, scriptPackScanList.getScanFileName(), scriptPackScanList.getId(), resultSql, i+1, "service");
                } catch (Exception e) {
                    log.error("业务脚本文件["+ scriptPackScanList.getScanFileName() +"]第[" + i+1 + "]块解析异常,请检查SQL是否规范");
                    List<ScriptPackScanResultEntity> scriptPackScanItemResult = new ArrayList<>(scriptPackScanResultMap.values())
                            .stream().map(s -> s.setScanState("antlrFail")).collect(Collectors.toList());
                    fileAllScanResult.addAll(scriptPackScanItemResult);
                    jointInfo(scriptPackScanItemResult, scriptPackScanList.getScanFileName(), scriptPackScanList.getId(), sourceSqlList.get(i), i+1, "service");
                }
            }
            String lastState = updateScanStatus(scriptPackScanList.getId(), fileAllScanResult, "success");
            updateTaskStateNum(scriptPackScanList.getScriptPackTaskId(), lastState);
        } catch (Exception e) {
            log.error("初始化脚本文件["+ scriptPackScanList.getScanFileName() +"]扫描出现异常：{}", e.getMessage(), e);
            scriptPackScanListService.updateStatus(scriptPackScanList.getId(), "FAIL");
            scriptPackTaskService.modifyScanErrorNum(scriptPackScanList.getScriptPackTaskId());
        }
    }

    /**
     * @Method scanPeriodScriptFile
     * @Param
     * @param scriptPackScanItemList
     * @param scriptPackScanList
     * @Return void
     * @Description 异步扫描周期脚本文件
     * @Author Wang zhihao
     * @Date 2023/10/12 17:51
     * @Version V1.0
     */
    @Override
    @Async("scriptScanAsyncTaskExecutor")
    public void scanPeriodScriptFile(List<ScriptPackScanItemEntity> scriptPackScanItemList, List<ScriptPackScanItemEntity> scriptPackScanHqlItemList, ScriptPackScanListEntity scriptPackScanList, List<String> timePartitionTableList, String clusterName) {
        List<ScriptPackScanResultEntity> fileAllScanResult = new ArrayList<>();
        scriptPackScanListService.updateStatus(scriptPackScanList.getId(), "SCANNING");
        log.info("==========【周期脚本文件" +scriptPackScanList.getScanFileName()+ "扫描开始】==========");
        try {
            List<String> sourceSqlList = getSqlByReadFile(scriptPackScanList.getScanFilePath());
            // 获取初始化脚本格式扫描对象 -- 20240417需求(hive_sql脚本无需检查其他项)
            String envScanResult = "success";
            if (!scriptPackScanList.getScanFileName().endsWith(FileScanEnum.HQL_SUFFIX.getValue())) {
                Map<String, ScriptPackScanResultEntity> scriptPackScanResultMap = initPeriodFormatScript(scriptPackScanItemList, scriptPackScanList);
                envScanResult = getFormatScanResult(sourceSqlList, scriptPackScanList, scriptPackScanResultMap);
            }
            for (int i=0; i < sourceSqlList.size(); i++) {
                // 初始化扫描结果sql扫描对象
                Map<String, ScriptPackScanResultEntity> newScriptPackScanResultMap = initPeriodScript(scriptPackScanItemList, scriptPackScanHqlItemList, scriptPackScanList);
                try {
                    // antlr解析SQL结果
                    Map<String, List<ScriptPackScanResultEntity>> scriptPackScanItemResultMap = getScanResultMap(sourceSqlList.get(i), scriptPackScanList.getScanFilePath(), scriptPackScanList.getScanFileName(), newScriptPackScanResultMap, timePartitionTableList, clusterName);
                    List<ScriptPackScanResultEntity> scriptPackScanItemResult = CollUtil.getFirst(scriptPackScanItemResultMap.values());
                    String resultSql = CollUtil.getFirst(scriptPackScanItemResultMap.keySet());
                    fileAllScanResult.addAll(scriptPackScanItemResult);
                    jointInfo(scriptPackScanItemResult, scriptPackScanList.getScanFileName(), scriptPackScanList.getId(), resultSql, i+1, "period");
                } catch (Exception e) {
                    log.error("周期脚本文件["+ scriptPackScanList.getScanFileName() +"]第[" + i+1 + "]块解析异常,请检查SQL是否规范");
                    List<ScriptPackScanResultEntity> scriptPackScanItemResult = new ArrayList<>(newScriptPackScanResultMap.values())
                            .stream().map(s -> s.setScanState("antlrFail")).collect(Collectors.toList());
                    fileAllScanResult.addAll(scriptPackScanItemResult);
                    jointInfo(scriptPackScanItemResult, scriptPackScanList.getScanFileName(), scriptPackScanList.getId(), sourceSqlList.get(i), i+1, "period");
                }
            }
            String lastState = updateScanStatus(scriptPackScanList.getId(), fileAllScanResult, envScanResult);
            updateTaskStateNum(scriptPackScanList.getScriptPackTaskId(), lastState);
        } catch (Exception e) {
            log.error("周期脚本文件["+ scriptPackScanList.getScanFileName() +"]扫描出现异常：{}", e.getMessage(), e);
            scriptPackScanListService.updateStatus(scriptPackScanList.getId(), "FAIL");
            scriptPackTaskService.modifyScanErrorNum(scriptPackScanList.getScriptPackTaskId());
        }
    }

    /**
     * @Method refreshTaskState
     * @Param
     * @param taskId
     * @Return void
     * @Description 刷新任务状态
     * @Author Wang zhihao
     * @Date 2023/10/24 14:54
     * @Version V1.0
     */
    @Override
    public void refreshTaskState(String taskId) {
        List<ScriptPackScanListEntity> scriptPackScanListEntities = scriptPackScanListService
                .queryListNoPage(new ScriptPackScanListEntity().setScriptPackTaskId(taskId));
        if (scriptPackScanListEntities.stream().noneMatch(s -> "SCANNING".equals(s.getScanState()))) {
            scriptPackTaskService.updateById(new ScriptPackTaskEntity().setId(taskId).setPackState("SCANFINISH"));
        }
    }


    /**
     * @Method getSqlByReadFile
     * @Param
     * @param filePath
     * @Return java.util.List<java.lang.String>
     * @Description 读取代码并剔除被/*注释的代码， 然后以";"分割返回代码块
     * @Author Wang zhihao
     * @Date 2023/10/20 18:19
     * @Version V1.0
     */
    @Override
    public List<String> getSqlByReadFile(String filePath) {
        try {
            String sourceSql = FileUtil.readUtf8String(filePath);
            // ① 用正则匹配的方式将被/*包括的sql语句剔除(多行注释的也可以)
            String noCommentSql = regexRemoveComment(sourceSql);
            // ② 去除被 --注释掉的行
            String noGeneralCommentSql = removeUnuseSql(noCommentSql);
            // ③ 新的截断方式
            List<String> sqlList = isqlExtractor.extractor(noGeneralCommentSql);
            return sqlList.stream().filter(s -> StrUtil.isNotEmpty(s.trim())).collect(Collectors.toList());
        } catch (Exception e) {
            log.error("脚本去除注释拆分文件出现异常：{}", e.getMessage(), e);
            throw new RuntimeException("脚本去除注释拆分文件出现异常：" + e.getMessage(), e);
        }
    }

    public List<String> getSqlByReadFileNoSplit(String filePath) {
        try {
            List<String> sqls = new ArrayList<>();
            String sourceSql = FileUtil.readUtf8String(filePath);
            sqls.add(sourceSql);
            return sqls;
        } catch (Exception e) {
            log.error("脚本读取出现异常：{}", e.getMessage(), e);
            throw new RuntimeException("脚本读取出现异常：" + e.getMessage(), e);
        }
    }

    /**
     * @Method regexRemoveComment
     * @Param
     * @param sourceSql
     * @Return java.lang.String
     * @Description 用正则匹配的方式将/*与--类型的注释语句删除
     * @Author Wang zhihao
     * @Date 2023/10/27 10:54
     * @Version V1.0
     */
    private String regexRemoveComment(String sourceSql) {
        Pattern pattern = Pattern.compile("/\\*[\\s\\S]*?\\*/", Pattern.MULTILINE | Pattern.DOTALL);
        Matcher matcher = pattern.matcher(sourceSql);
        sourceSql = matcher.replaceAll("");
        return sourceSql;
    }

    private String removeUnuseSql(String sourceSql) {
        List<String> sqlLine = Arrays.stream(sourceSql.split("\n")).collect(Collectors.toList());
        List<String> usefulSqlLine = sqlLine.stream().filter(s -> !StrUtil.startWith(s.trim(), "--")).collect(Collectors.toList());
        return String.join("\n", usefulSqlLine);
    }

    /**
     * @Method initInitScript
     * @Param
     * @param scriptPackScanItemList
     * @Return java.util.Map<java.lang.String,com.hex.ds.code.detection.component.code.detection.model.ScriptPackScanResult>
     * @Description 初始化脚本扫描项初始化
     * @Author Wang zhihao
     * @Date 2023/10/10 9:34
     * @Version V1.0
     */
    private Map<String, ScriptPackScanResultEntity> initInitScript(List<ScriptPackScanItemEntity> scriptPackScanItemList, List<ScriptPackScanItemEntity> scriptPackScanHqlItemList, ScriptPackScanListEntity scriptPackScanList) {
        List<ScriptPackScanResultEntity> scriptPackScanResultList = new ArrayList<>();
        if (scriptPackScanList.getScanFileName().endsWith(FileScanEnum.HQL_SUFFIX.getValue())) {
            scriptPackScanResultList = turnToResult(scriptPackScanHqlItemList);
        } else {
            scriptPackScanResultList = turnToResult(scriptPackScanItemList);
        }
        return scriptPackScanResultList.stream()
                .map(s -> s.setScanTaskId(scriptPackScanList.getScriptPackTaskId()))
                .map(s -> s.setScanState("success"))
                .map(s -> s.setScanTable("default"))
                .collect(Collectors.toMap(ScriptPackScanResultEntity::getScanItem, Function.identity()));
    }

    /**
     * @Method initServiceScript
     * @Param
     * @param scriptPackScanItemList
     * @Return java.util.Map<java.lang.String,com.hex.ds.code.detection.component.code.detection.entity.ScriptPackScanResultEntity>
     * @Description 业务脚本扫描项初始化
     * @Author Wang zhihao
     * @Date 2023/10/11 10:55
     * @Version V1.0
     */
    private Map<String, ScriptPackScanResultEntity> initServiceScript(List<ScriptPackScanItemEntity> scriptPackScanItemList, String taskId) {
        List<ScriptPackScanResultEntity> scriptPackScanResultList = turnToResult(scriptPackScanItemList);
        return scriptPackScanResultList.stream()
                .map(s -> s.setScanTaskId(taskId))
                .map(s -> s.setScanState(StrUtil.containsAnyIgnoreCase(s.getScanItem(), "commitCheck") ? "warning" : "success"))
                .map(s -> s.setScanTable("default"))
                .collect(Collectors.toMap(ScriptPackScanResultEntity::getScanItem, Function.identity()));
    }

    /**
     * @Method initPeriodScript
     * @Param
     * @param scriptPackScanItemList
     * @Return java.util.Map<java.lang.String,com.hex.ds.code.detection.component.code.detection.model.ScriptPackScanResult>
     * @Description 周期脚本扫描项初始化
     * @Author Wang zhihao
     * @Date 2023/10/10 9:34
     * @Version V1.0
     */
    private Map<String, ScriptPackScanResultEntity> initPeriodScript(List<ScriptPackScanItemEntity> scriptPackScanItemList, List<ScriptPackScanItemEntity> scriptPackScanHqlItemList, ScriptPackScanListEntity scriptPackScanList) {
        List<ScriptPackScanResultEntity> scriptPackScanResultList = new ArrayList<>();
        if (scriptPackScanList.getScanFileName().endsWith(FileScanEnum.HQL_SUFFIX.getValue())) {
            scriptPackScanResultList = turnToResult(scriptPackScanHqlItemList);
        } else {
            scriptPackScanResultList = turnToResult(scriptPackScanItemList);
        }
        return scriptPackScanResultList.stream()
                .map(s -> s.setScanTaskId(scriptPackScanList.getScriptPackTaskId()))
                .map(s -> s.setScanState(StrUtil.containsAnyIgnoreCase(s.getScanItem(), "computeCheck", "refreshCheck") ? "default" : "success"))
                .map(s -> s.setScanTable("default"))
                .collect(Collectors.toMap(ScriptPackScanResultEntity::getScanItem, Function.identity()));
    }

    /**
     * @Method initPeriodFormatScript
     * @Param
     * @param scriptPackScanItemList
     * @param scriptPackScanList
     * @Return java.util.Map<java.lang.String,com.hex.ds.code.detection.component.code.detection.entity.ScriptPackScanResultEntity>
     * @Description 初始化周期脚本扫描项
     * @Author Wang zhihao
     * @Date 2023/12/28 14:22
     * @Version V1.0
     */
    private Map<String, ScriptPackScanResultEntity> initPeriodFormatScript(List<ScriptPackScanItemEntity> scriptPackScanItemList, ScriptPackScanListEntity scriptPackScanList) {
        List<ScriptPackScanResultEntity> scriptPackScanResultList = turnToFormatResult(scriptPackScanItemList);
/*        // 定制化 => hql结尾的文件排掉刷新表和统计表操作
        if (CollectionUtil.isNotEmpty(scriptPackScanResultList) && StrUtil.endWith(scriptPackScanList.getScanFileName(), ".hql")) {
            scriptPackScanResultList = scriptPackScanResultList.stream().filter(s -> !StrUtil.equalsAny(s.getScanItem(), AntlrEnum.REFRESH_CHECK.getValue(), AntlrEnum.COMPUTE_CHECK.getValue())).collect(Collectors.toList());
        }*/
        return scriptPackScanResultList.stream()
                .map(s -> s.setScanTaskId(scriptPackScanList.getScriptPackTaskId()))
                .map(s -> s.setScanState(StrUtil.containsAnyIgnoreCase(s.getScanItem(), "computeCheck", "refreshCheck") ? "default" : "success"))
                .map(s -> s.setScanTable("default"))
                .collect(Collectors.toMap(ScriptPackScanResultEntity::getScanItem, Function.identity()));
    }

    /**
     * @Method initShellScript
     * @Param
     * @param scriptPackScanItemList
     * @param taskId
     * @Return java.util.Map<java.lang.String,com.hex.ds.code.detection.component.code.detection.entity.ScriptPackScanResultEntity>
     * @Description 初始化Shell脚本扫描项
     * @Author Wang zhihao
     * @Date 2024/1/30 11:34
     * @Version V1.0
     */
    private Map<String, ScriptPackScanResultEntity> initShellScript(List<ScriptPackScanItemEntity> scriptPackScanItemList, String taskId) {
        List<ScriptPackScanResultEntity> scriptPackScanResultList = turnToResult(scriptPackScanItemList);
        return scriptPackScanResultList.stream()
                .map(s -> s.setScanTaskId(taskId))
                .map(s -> s.setScanState("success"))
                .map(s -> s.setScanTable("default"))
                .collect(Collectors.toMap(ScriptPackScanResultEntity::getScanItem, Function.identity()));
    }

    /**
     * @Method turnToResult
     * @Param
     * @param scriptPackScanItemList
     * @Return java.util.List<com.hex.ds.code.detection.component.code.detection.model.ScriptPackScanResult>
     * @Description 模板对象维护为result对象
     * @Author Wang zhihao
     * @Date 2023/10/8 13:35
     * @Version V1.0
     */
    private List<ScriptPackScanResultEntity> turnToResult(List<ScriptPackScanItemEntity> scriptPackScanItemList) {
        List<ScriptPackScanResultEntity> scriptPackScanResults = new ArrayList<>();
        List<ScriptPackScanItemEntity> formatList = scriptPackScanItemList.stream().filter(s -> !"format".equals(s.getScanType())).collect(Collectors.toList());
        for (ScriptPackScanItemEntity scriptPackScanItem : formatList) {
            ScriptPackScanResultEntity scriptPackScanResult = new ScriptPackScanResultEntity()
                    .setScanState(scriptPackScanItem.getScanState())
                    .setScanTable(scriptPackScanItem.getScanTable())
                    .setSqlType(scriptPackScanItem.getSqlType())
                    .setScanLevel(scriptPackScanItem.getScanLevel())
                    .setScanItem(scriptPackScanItem.getScanName())
                    .setScanItemDescribe(scriptPackScanItem.getScanDesc())
                    .setScanDescInfo(scriptPackScanItem.getScanDescInfo());
            scriptPackScanResults.add(scriptPackScanResult);
        }
        return scriptPackScanResults;
    }

    private List<ScriptPackScanResultEntity> turnToFormatResult(List<ScriptPackScanItemEntity> scriptPackScanItemList) {
        List<ScriptPackScanResultEntity> scriptPackScanResults = new ArrayList<>();
        List<ScriptPackScanItemEntity> formatList = scriptPackScanItemList.stream().filter(s -> "format".equals(s.getScanType())).collect(Collectors.toList());
        for (ScriptPackScanItemEntity scriptPackScanItem : formatList) {
            ScriptPackScanResultEntity scriptPackScanResult = new ScriptPackScanResultEntity()
                    .setScanState(scriptPackScanItem.getScanState())
                    .setScanTable(scriptPackScanItem.getScanTable())
                    .setSqlType(scriptPackScanItem.getSqlType())
                    .setScanLevel(scriptPackScanItem.getScanLevel())
                    .setScanItem(scriptPackScanItem.getScanName())
                    .setScanItemDescribe(scriptPackScanItem.getScanDesc())
                    .setScanDescInfo(scriptPackScanItem.getScanDescInfo());
            scriptPackScanResults.add(scriptPackScanResult);
        }
        return scriptPackScanResults;
    }

    /**
     * @Method getScanResult
     * @Param
     * @param sql
     * @param filePath
     * @Return java.util.List<com.hex.ds.code.detection.component.code.detection.model.ScriptPackScanItem>
     * @Description 通过Antlr按扫描清单扫描得出对应的结果信息
     * @Author Wang zhihao
     * @Date 2023/9/27 16:35
     * @Version V1.0
     */
    private Map<String, List<ScriptPackScanResultEntity>> getScanResultMap(String sql, String filePath, String fileName, Map<String, ScriptPackScanResultEntity> scriptPackScanResultMap, List<String> timePartitionTableList, String clusterName) {
        try {
            Map<String, List<ScriptPackScanResultEntity>> resultMap = new HashMap<>();
            Map<String, String> paramsConfig = configService.getParam(clusterName);
            HiveBaseSqlVisitor hiveBaseSqlVisitor = new HiveBaseSqlVisitor();
            // 获取扫描标记后的SQL信息
            String targetSql = hiveBaseSqlVisitor.visitRoot(sql, scriptPackScanResultMap, timePartitionTableList, paramsConfig, fileName);
            // 获取扫描项结果信息
            List<ScriptPackScanResultEntity> scriptPackScanResultList = hiveBaseSqlVisitor.getScriptPackScanResultList();
            // 获取是否语法解析存在异常信息
            boolean isAnalyticException = hiveBaseSqlVisitor.getIsAnalyticException();
            if (isAnalyticException) {
                scriptPackScanResultList = scriptPackScanResultList.stream().map(s -> s.setScanState("badSql")).collect(Collectors.toList());
            }
            resultMap.put(targetSql, scriptPackScanResultList);
            return resultMap;
        } catch (Exception e) {
            log.error("代码解析时发生异常,请检查代码语句是否规范,路径：{},报错信息 {}", filePath ,e.getMessage(), e);
            throw new RuntimeException("代码解析时发生异常,请检查代码语句是否规范,路径：" + filePath + "报错信息:" + e.getMessage(), e);
        }
    }

    /**
     * @Method getScanOracleResultMap
     * @Param
     * @param sql
     * @param filePath
     * @param scriptPackScanResultMap
     * @Return java.util.List<com.hex.ds.code.detection.component.code.detection.entity.ScriptPackScanResultEntity>
     * @Description 通过Antlr按扫描清单扫描得出对应的结果信息(Oracle版)
     * @Author Wang zhihao
     * @Date 2023/10/30 11:03
     * @Version V1.0
     */
    private Map<String, List<ScriptPackScanResultEntity>> getScanOracleResultMap(String sql, String filePath, Map<String, ScriptPackScanResultEntity> scriptPackScanResultMap, String clusterName) {
        try {
            Map<String, List<ScriptPackScanResultEntity>> resultMap = new HashMap<>();
            Map<String,String> config = configService.getParam(clusterName);
            OracleBasicSqlVisitor oracleBasicSqlVisitor = new OracleBasicSqlVisitor();
            // 其他扫描项返回处理后的SQL
            String resultStr = oracleBasicSqlVisitor.visitRoot(sql, scriptPackScanResultMap, config);
            // value中值的内容扫描后需替换的SQL(用于返回推送下载稽核脚本中嵌套的SQL处理结果)
            Map<String, String> remarkSqlMap = oracleBasicSqlVisitor.getRemarkSqlMap();
            resultStr = remarkSqlMap.entrySet().stream()
                    .reduce(resultStr, (result, entry) -> result.replace(entry.getKey(), entry.getValue()), (a, b) -> a);
            // 获取扫描项结果信息
            List<ScriptPackScanResultEntity> scriptPackScanResultList = oracleBasicSqlVisitor.getScriptPackScanResultList();
            // 获取是否语法解析存在异常信息
            boolean isAnalyticException = oracleBasicSqlVisitor.getIsAnalyticException();
            if (isAnalyticException) {
                scriptPackScanResultList = scriptPackScanResultList.stream().map(s -> s.setScanState("badSql")).collect(Collectors.toList());
            }
            resultMap.put(SqlFormatterUtil.formatterSqlWithSpace(resultStr), scriptPackScanResultList);
            return resultMap;
        } catch (Exception e) {
            throw new RuntimeException("代码解析时发生异常,请检查代码语句是否规范,路径：" + filePath);
        }
    }

    /**
     * @Method jointInfo
     * @Param
     * @param results
     * @param fileName
     * @param listPkId
     * @param sourceSql
     * @param sqlIndex
     * @param fileType
     * @Return void
     * @Description 配置信息
     * @Author Wang zhihao
     * @Date 2023/10/9 11:21
     * @Version V1.0
     */
    private void jointInfo(List<ScriptPackScanResultEntity> results, String fileName, String listPkId, String sourceSql, int sqlIndex, String fileType) {
        for (ScriptPackScanResultEntity result : results) {
            result.setScanListId(listPkId)
                    .setFileName(fileName)
                    .setFileType(fileType)
                    .setScanSql(sourceSql)
                    .setScanSqlIndex(String.valueOf(sqlIndex));
        }
        scriptPackScanResultService.saveBatch(results);
    }

    /**
     * @Method updateScanStatus
     * @Param listPkId
     * @param fileAllScanResult
     * @Return String
     * @Description 更新列表扫描状态
     * @Author Wang zhihao
     * @Date 2023/10/8 13:52
     * @Version V1.0
     */
    private String updateScanStatus(String listPkId, List<ScriptPackScanResultEntity> fileAllScanResult, String envScanResult) {
        // 提取出所有的扫描结果并将环境扫描结果也加入到里面
        List<String> stateList = fileAllScanResult.stream().map(ScriptPackScanResultEntity::getScanState).collect(Collectors.toList());
        stateList.add(envScanResult);
        // 汇总统计信息
        String lastState = stateList.stream().anyMatch(state -> StrUtil.equalsAny(state, "fail", "antlrFail", "badSql")) ? "FAIL"
                : stateList.stream().anyMatch(state -> state.equals("warning")) ? "WARNING"
                : "SUCCESS";
        scriptPackScanListService.updateStatus(listPkId, lastState);
        return lastState;
    }

    /**
     * @Method updateTaskStateNum
     * @Param
     * @param taskId
     * @param state
     * @Return void
     * @Description 根据状态更新任务状态数
     * @Author Wang zhihao
     * @Date 2024/1/31 13:23
     * @Version V1.0
     */
    private void updateTaskStateNum(String taskId, String state) {
        switch (state.toUpperCase(Locale.ROOT)) {
            case "SUCCESS":
                scriptPackTaskService.modifyScanSuccessNum(taskId);
                break;
            case "WARNING":
                scriptPackTaskService.modifyScanWarnNum(taskId);
                break;
            default:
                scriptPackTaskService.modifyScanErrorNum(taskId);
                break;
        }
    }

    /**
     * @Method getFormatScanResult
     * @Param
     * @param sourceSqlList
     * @Return java.util.List<java.lang.String>
     * @Description 获取环境信息检查
     * @Author Wang zhihao
     * @Date 2023/10/30 15:37
     * @Version V1.0
     */
    private String getFormatScanResult(List<String> sourceSqlList, ScriptPackScanListEntity scriptPackScanList, Map<String, ScriptPackScanResultEntity> scriptPackScanResultMap) {
        // 扫描Set配置
        String setScanState = scanSetInfo(sourceSqlList, scriptPackScanList, scriptPackScanResultMap);
        // 扫描IP配置
        String ipScanState = ipSetInfo(sourceSqlList, scriptPackScanList, scriptPackScanResultMap);
        // 扫描refresh配置
        String refreshScanState = scanRefreshInfo(sourceSqlList, scriptPackScanList, scriptPackScanResultMap);
        // 扫描compute配置
        String computeScanState = scanComputeInfo(sourceSqlList, scriptPackScanList, scriptPackScanResultMap);
        return checkEnvState(setScanState, ipScanState, refreshScanState, computeScanState);
    }

    /**
     * @Method checkEnvState
     * @Param
     * @param states
     * @Return java.lang.String
     * @Description 检查各项环境扫描情况并返回统计结果
     * @Author Wang zhihao
     * @Date 2023/12/25 15:08
     * @Version V1.0
     */
    private String checkEnvState(String... states) {
        List<String> stateList = Arrays.stream(states).collect(Collectors.toList());
        return stateList.stream().anyMatch(state -> state.equals("fail")) ? "fail"
                : stateList.stream().anyMatch(state -> state.equals("warning")) ? "warning"
                : "success";
    }

    /**
     * @Method ipSetInfo
     * @Param
     * @param scriptPackScanList
     * @param scriptPackScanResultMap
     * @Return void
     * @Description 扫描IP配置
     * @Author Wang zhihao
     * @Date 2023/11/2 20:48
     * @Version V1.0
     */
    private String ipSetInfo(List<String> sourceSqlList, ScriptPackScanListEntity scriptPackScanList, Map<String, ScriptPackScanResultEntity> scriptPackScanResultMap) {
        if (scriptPackScanResultMap.containsKey(FileScanEnum.IP_CHECK.getValue())) {
            String sourceSql = sourceSqlList.stream().collect(Collectors.joining(System.lineSeparator()));
            String regex = "\\d+\\.\\d+\\.\\d+\\.\\d+";
            Pattern pattern = Pattern.compile(regex);
            Matcher matcher = pattern.matcher(sourceSql);
            boolean isSuccess = !matcher.find();
            ScriptPackScanResultEntity scriptPackScanResult = scriptPackScanResultMap.get(FileScanEnum.IP_CHECK.getValue());
            addScanResultInfo("", scriptPackScanResult, scriptPackScanList, isSuccess, scriptPackScanResult.getScanLevel());
            return isSuccess ? "success" : ( StrUtil.equalsIgnoreCase(scriptPackScanResult.getScanLevel(), "necessary") ? "fail" : "warning" );
        } else {
            return "success";
        }
    }

    /**
     * @Method scanSetInfo
     * @Param
     * @param sourceSqlList
     * @param scriptPackScanList
     * @param scriptPackScanResultMap
     * @Return java.lang.String
     * @Description 检验set配置
     * @Author Wang zhihao
     * @Date 2023/12/28 18:10
     * @Version V1.0
     */
    private String scanSetInfo(List<String> sourceSqlList, ScriptPackScanListEntity scriptPackScanList, Map<String, ScriptPackScanResultEntity> scriptPackScanResultMap) {
        // 筛选出以set开头的环境配置sql
        List<String> setValues = new ArrayList<>();
        String allSql = String.join("\n", sourceSqlList);
        Pattern pattern = Pattern.compile("set\\s+(\\S+)\\s*=\\s*(\\S+);");
        Matcher matcher = pattern.matcher(allSql.trim());
        while (matcher.find()) {
            String setValue = matcher.group();
            setValues.add(setValue);
        }
        if (CollectionUtil.isNotEmpty(setValues)) {
            sourceSqlList.removeAll(setValues);
        }
        return scanEnvInfo(setValues, scriptPackScanList, scriptPackScanResultMap);
    }

    /**
     * @Method scanEnvInfo
     * @Param
     * @param setEnvList
     * @param scriptPackScanList
     * @param scriptPackScanResultMap
     * @Return java.lang.String
     * @Description 返回set扫描结果
     * @Author Wang zhihao
     * @Date 2023/12/28 18:10
     * @Version V1.0
     */
    private String scanEnvInfo(List<String> setEnvList, ScriptPackScanListEntity scriptPackScanList, Map<String, ScriptPackScanResultEntity> scriptPackScanResultMap) {
        if (scriptPackScanResultMap.containsKey(FileScanEnum.SET_ENV_CHECK.getValue())) {
            boolean isParamSet = CollectionUtil.isEmpty(setEnvList) ? true :
                    setEnvList.stream().map(s -> StringUtils.replaceChars(s, " \n\r\t", "").toUpperCase()).noneMatch(s -> s.trim().startsWith("SETMEM_LIMIT="));
            String sql = CollectionUtil.isEmpty(setEnvList) ? "" : StrUtil.join(";\n", setEnvList);
            ScriptPackScanResultEntity scriptPackScanResult = scriptPackScanResultMap.get(FileScanEnum.SET_ENV_CHECK.getValue());
            addScanResultInfo(sql, scriptPackScanResult, scriptPackScanList, isParamSet, scriptPackScanResult.getScanLevel());
            return isParamSet ? "success" : ( StrUtil.equalsIgnoreCase(scriptPackScanResult.getScanLevel(), "necessary") ? "fail" : "warning" );
        } else {
            return "success";
        }
    }

    /**
     * @Method scanRefreshInfo
     * @Param
     * @param sourceSqlList
     * @param scriptPackScanList
     * @param scriptPackScanResultMap
     * @Return java.util.List<java.lang.String>
     * @Description 扫描refresh配置
     * @Author Wang zhihao
     * @Date 2023/11/6 16:36
     * @Version V1.0
     */
    private String scanRefreshInfo(List<String> sourceSqlList, ScriptPackScanListEntity scriptPackScanList, Map<String, ScriptPackScanResultEntity> scriptPackScanResultMap) {
        List<String> refreshList = new ArrayList<>();
        for (String sourceSql : sourceSqlList) {
            List<String> sqlLine = Arrays.stream(sourceSql.split("\n")).collect(Collectors.toList());
            if (sqlLine.stream().anyMatch(s -> s.trim().toLowerCase().startsWith("refresh"))) {
                refreshList.add(sourceSql);
            }
        }
        sourceSqlList.removeAll(refreshList);
        return scanRefreshExists(refreshList, scriptPackScanList, scriptPackScanResultMap);
    }

    /**
     * @Method scanRefreshExists
     * @Param 
     * @param refreshList
     * @param scriptPackScanList
     * @param scriptPackScanResultMap 
     * @Return void
     * @Description 扫描refresh是否存在
     * @Author Wang zhihao
     * @Date 2023/11/6 16:36
     * @Version V1.0
     */
    private String scanRefreshExists(List<String> refreshList, ScriptPackScanListEntity scriptPackScanList, Map<String, ScriptPackScanResultEntity> scriptPackScanResultMap) {
        if (scriptPackScanResultMap.containsKey(FileScanEnum.REFRESH_CHECK.getValue())) {
            boolean isRefreshExists = CollectionUtil.isNotEmpty(refreshList);
            String sql = StrUtil.join(";\n", refreshList);
            ScriptPackScanResultEntity scriptPackScanResult = scriptPackScanResultMap.get(FileScanEnum.REFRESH_CHECK.getValue());
            addScanResultInfo(sql, scriptPackScanResult, scriptPackScanList, isRefreshExists, scriptPackScanResult.getScanLevel());
            return isRefreshExists ? "success" : ( StrUtil.equalsIgnoreCase(scriptPackScanResult.getScanLevel(), "necessary") ? "fail" : "warning" );
        } else {
            return "success";
        }
    }

    /**
     * @Method scanComputeInfo
     * @Param
     * @param sourceSqlList
     * @param scriptPackScanList
     * @param scriptPackScanResultMap
     * @Return java.util.List<java.lang.String>
     * @Description 扫描compute配置
     * @Author Wang zhihao
     * @Date 2023/11/6 16:36
     * @Version V1.0
     */
    private String scanComputeInfo(List<String> sourceSqlList, ScriptPackScanListEntity scriptPackScanList, Map<String, ScriptPackScanResultEntity> scriptPackScanResultMap) {
        List<String> refreshList = new ArrayList<>();
        for (String sourceSql : sourceSqlList) {
            List<String> sqlLine = Arrays.stream(sourceSql.split("\n")).collect(Collectors.toList());
            if (sqlLine.stream().anyMatch(s -> s.trim().toLowerCase().startsWith("compute"))) {
                refreshList.add(sourceSql);
            }
        }
        sourceSqlList.removeAll(refreshList);
        return scanComputeExists(refreshList, scriptPackScanList, scriptPackScanResultMap);
    }

    /**
     * @Method scanComputeExists
     * @Param
     * @param computeList
     * @param scriptPackScanList
     * @param scriptPackScanResultMap
     * @Return void
     * @Description 扫描compute是否存在
     * @Author Wang zhihao
     * @Date 2023/11/6 16:36
     * @Version V1.0
     */
    private String scanComputeExists(List<String> computeList, ScriptPackScanListEntity scriptPackScanList, Map<String, ScriptPackScanResultEntity> scriptPackScanResultMap) {
        if (scriptPackScanResultMap.containsKey(FileScanEnum.COMPUTE_CHECK.getValue())) {
            boolean isRefreshExists = CollectionUtil.isNotEmpty(computeList);
            String sql = StrUtil.join(";\n", computeList);
            ScriptPackScanResultEntity scriptPackScanResult = scriptPackScanResultMap.get(FileScanEnum.COMPUTE_CHECK.getValue());
            addScanResultInfo(sql, scriptPackScanResult, scriptPackScanList, isRefreshExists, scriptPackScanResult.getScanLevel());
            return isRefreshExists ? "success" : ( StrUtil.equalsIgnoreCase(scriptPackScanResult.getScanLevel(), "necessary") ? "fail" : "warning" );
        } else {
            return "success";
        }
    }

    /**
     * @Method addScanResultInfo
     * @Param
     * @param sql
     * @param scriptPackScanResult
     * @param scriptPackScanList
     * @param isSuccess
     * @Return void
     * @Description 添加格式扫描结果信息
     * @Author Wang zhihao
     * @Date 2023/11/2 20:55
     * @Version V1.0
     */
    private void addScanResultInfo(String sql, ScriptPackScanResultEntity scriptPackScanResult, ScriptPackScanListEntity scriptPackScanList, boolean isSuccess, String level) {
        try {
            scriptPackScanResult.setScanListId(scriptPackScanList.getId())
                    .setScanTaskId(scriptPackScanList.getScriptPackTaskId())
                    .setScanState(isSuccess ? "success" : (level.equalsIgnoreCase("necessary") ? "fail" : "warning"))
                    .setFileType(scriptPackScanList.getScanFileName())
                    .setFileType(scriptPackScanList.getFileAffiliation())
                    .setFileName(scriptPackScanList.getScanFileName())
                    .setScanSql(sql)
                    .setScanSqlIndex("0");
            scriptPackScanResultService.save(scriptPackScanResult);
        } catch (Exception e) {
            log.error("格式扫描结果信息添加异常:{}" , e.getMessage(), e);
            throw new RuntimeException("格式扫描结果信息添加异常:" + e.getMessage(), e);
        }
    }

    private void addScanResultInfo(String sql, ScriptPackScanResultEntity scriptPackScanResult, ScriptPackScanListEntity scriptPackScanList, String errorType) {
        try {
            scriptPackScanResult.setScanListId(scriptPackScanList.getId())
                    .setScanTaskId(scriptPackScanList.getScriptPackTaskId())
                    .setScanState(errorType)
                    .setFileType(scriptPackScanList.getScanFileName())
                    .setFileType(scriptPackScanList.getFileAffiliation())
                    .setFileName(scriptPackScanList.getScanFileName())
                    .setScanSql(sql)
                    .setScanSqlIndex("0");
            scriptPackScanResultService.save(scriptPackScanResult);
        } catch (Exception e) {
            log.error("格式扫描结果信息添加异常:{}" , e.getMessage(), e);
            throw new RuntimeException("格式扫描结果信息添加异常:" + e.getMessage(), e);
        }
    }

    /**
     * @Method getShellFileType
     * @Param
     * @param filePath
     * @Return java.lang.String
     * @Description 获取Shell文件类型
     * @Author Wang zhihao
     * @Date 2024/1/29 20:00
     * @Version V1.0
     */
    private String getShellFileType(String filePath) {
        String fileType = "unknown";
        Process process = null;
        try {
            // 创建进程构建器
            String command = "head -n 2 " + filePath + " | cat -A";
            ProcessBuilder builder = new ProcessBuilder("/bin/bash", "-c", command);
//            ProcessBuilder builder = new ProcessBuilder("cat", "-A", filePath);
            builder.redirectErrorStream(true);

            // 启动进程并获取输出
            process = builder.start();

            // 设置超时时间为20秒
            boolean finished = process.waitFor(20, TimeUnit.SECONDS);
            if (finished) {
                log.info("进程执行完成, 开始校验其文件类型");
                BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
                // 读取输出
                String line = reader.readLine();
                // 获取文件类型
                if (line.endsWith("^M$")) {
                    fileType = "dos";
                } else if (line.endsWith("$")){
                    fileType = "linux";
                } else {
                    fileType = "unknown";
                }
            } else {
                log.error("进程执行超时, 调用destroy()方法");
                process.destroy();
            }

            log.info("【获取Shell文件" + filePath + "类型】为" + fileType);
            return fileType;
        } catch (Exception e) {
            log.error("【获取Shell文件类型】异常: {}" + fileType, e.getMessage(), e);
            throw new RuntimeException("【获取Shell文件类型】异常: " + e.getMessage());
        } finally {
            try {
                log.warn("===========关闭连接");
                if (process != null && process.isAlive()) {
                    process.destroy();
                }
                log.warn("============关闭成功");
            } catch (Exception e) {
                log.warn("============关闭失败");
                e.printStackTrace();
            }
        }
    }

}
